﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VersionComparer.Base;

namespace VersionComparer.UI
{
    public class ItemsListRichTextBox : VersionComparer.ExtendedRichTextBox
    {
        Label lbl;

        Dictionary<string, bool> allKnownFiles = new Dictionary<string, bool>();
        Dictionary<string, bool> allKnownFolders = new Dictionary<string, bool>();
        Dictionary<string, string[]> knownfiles = new Dictionary<string, string[]>();

        public ItemsListRichTextBox()
            : base()
        {
            
            MinimumSize = new Size(200, 10);
            ShowLabel(true);
            WordWrap = false;
            AllowDrop = true;
            HideSelection = false;
            DetectUrls = false;
            EmptyMessage = "Insert new items to compare"; ;
        }

        public string EmptyMessage
        {
            get;
            set;
        }
        #region label related methods
        protected override void OnParentChanged(EventArgs e)
        {
            ShowLabel();
            base.OnParentChanged(e);
        }
        private void ShowLabel()
        {
            ShowLabel(String.IsNullOrEmpty(Text));
        }
        private void ShowLabel(bool show)
        {
            if (Parent == null)
                return;
            bool isVisible = lbl== null? false: lbl.Visible;
            if (show == isVisible)
                return;
            if (show)
            {
                lbl = new Label();
                lbl.BackColor = BackColor;
                lbl.Font = new Font(Font, FontStyle.Italic);
                lbl.ForeColor = Color.Gray;
                lbl.AutoSize = true;
                //lbl.BackColor = Color.FromArgb(0, 255, 255, 255);
                lbl.Text = EmptyMessage;
                lbl.Anchor = AnchorStyles.None;
                Parent.Controls.Add(lbl);
                lbl.Left = Width / 2 - lbl.Width / 2;
                lbl.Top = Height / 2 - lbl.Height / 2;
                lbl.BringToFront();
            }
            else
            {
                lbl.Visible = false;
                Parent.Controls.Remove(lbl);
                lbl = null;
            }
            
        }
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (lbl != null)
                lbl.Visible = Visible;
        }
        protected override void OnResize(EventArgs e)
        {
            if (lbl != null)
            {
                lbl.Left = Width / 2 - lbl.Width / 2;
                lbl.Top = Height / 2 - lbl.Height / 2;
            }
                
            base.OnResize(e);
        }
        
        #endregion label related methods
        
        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            ShowLabel();
        }

        #region syntax coloring
        protected override Color? GetLineColor(string line)
        {
            try
            {
                if (string.IsNullOrEmpty(line))
                    return Color.Gray;
                string folder = Path.GetDirectoryName ( line );
                string fileName = Path.GetFileName ( line );
                string subFolderName = fileName + "\\";
                
                string []files = GetFilesInFolder(folder);
                
                if ( files == null )
                    return Color.Gray;
                if (string.IsNullOrEmpty(fileName))
                    return Color.Blue;
                if (files.FirstOrDefault(x => string.Compare(fileName, x, true) == 0) != null)
                {
                    return Color.Green;
                }
                else
                {
                    if (files.FirstOrDefault(x => string.Compare(subFolderName, x, true) == 0) != null)
                        return Color.Blue;
                    else
                        return Color.Gray;
                }
            }
            catch
            {
                return Color.Gray;
            }
        }
        #endregion syntax coloring

        #region autocomplete
        protected override bool KeyAcceptsAutoComplete(Keys key)
        {
            //if ((int)key == 220)
            //    return true;
            return base.KeyAcceptsAutoComplete(key);
        }
        private void CheckFolder(ManagedThread threadManager , string folder)
        {
            if (Directory.Exists(folder))
            {
                List<string> allFiles = new List<string>();
                foreach (string value in Directory.GetFiles(folder))
                    allFiles.Add(Path.GetFileName(value));
                foreach (string value in Directory.GetDirectories(folder))
                    allFiles.Add(Path.GetFileName(value) + "\\");
                allFiles.Sort();
                lock (knownfiles)
                    knownfiles[folder] = allFiles.ToArray();
            }
            else
            {
                lock (knownfiles)
                    knownfiles[folder] = null;
            }
        }

        private string[] GetFilesInFolder(string folder)
        {
            if (string.IsNullOrEmpty(folder))
                return Directory.GetLogicalDrives();
            string[] folderItems;
            bool gotFiles;
            //this locking may be done this way because GetSuggestions allways runs on the same (UI) thread
            lock (knownfiles)
            {
                gotFiles = knownfiles.TryGetValue(folder, out folderItems);
            }
            if (!gotFiles)
            {
                lock (knownfiles)
                {
                    knownfiles.Add(folder, folderItems = new string[0]);
                }
                string name = "CheckFolder_" + Path.GetPathRoot(folder);
                ThreadManager.Current.StartNew(name, CheckFolder, folder);
                System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
                s.Start();
                bool result = ThreadManager.Current.WaitForThread(name, 200);
                double d1 = s.ElapsedMilliseconds;
                if (d1 > 200)
                {
                }
                lock (knownfiles)
                    return knownfiles[folder];
                

            }
            return folderItems;
        }
        protected override string GetSuggestions(string line, string suggestion)
        {
            if (!string.IsNullOrEmpty(line))
            {
                try
                {
                    if (line.EndsWith("t"))
                    {
                    }
                    string folder = Path.GetDirectoryName(line);
                    string file = Path.GetFileName(line);
                    string[] suggestions;
                    if (folder != null && file != null)
                    {

                        suggestions = GetFilesInFolder(folder);
                        if (suggestions != null)
                        {
                            for (int i = 0; i < suggestions.Length; i++)
                            {
                                string possibleSuggestion = suggestions[i];
                                if (possibleSuggestion.StartsWith(file, StringComparison.InvariantCultureIgnoreCase))
                                    return possibleSuggestion.Substring(file.Length).TrimEnd('\\');
                            }
                        }
                    }
                }
                catch
                {
                    return suggestion;
                }

                    
            }
            return base.GetSuggestions(line, suggestion);
        }
        #endregion autocomplete

        #region drag & drop related

        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            List<string> allfiles = new List<string>();
            string[] files = (string[])drgevent.Data.GetData("FileDrop");

            StringBuilder filesToAdd = new StringBuilder ();
            foreach (string file in files)
            {
                if (Directory.Exists(file))
                    allfiles.AddRange(Directory.GetFiles(file, "*.*", SearchOption.AllDirectories));
                else
                    allfiles.Add( file );
                
            }
            foreach (string file in allfiles)
                filesToAdd.AppendLine(file);

            int lineIndex = GetLineFromCharIndex(SelectionStart) + 1;
            if (lineIndex >= Lines.Length)
            {
                SelectionStart = Text.Length;
                if (Lines.Last().Length > 0 )
                    filesToAdd .Insert ( 0,"\r\n");
            }
            else
                SelectionStart = GetFirstCharIndexFromLine(lineIndex);

            int selectionStart = SelectionStart;
            this.SelectedText  = filesToAdd.ToString();

            int selectionLength = filesToAdd.ToString().Length - allfiles.Count;
            Select(selectionStart, selectionLength);
            base.OnDragDrop(drgevent);
        }
        protected override void OnDragOver(DragEventArgs drgevent)
        {
            base.OnDragOver(drgevent);
        }
        protected override void OnDragEnter(DragEventArgs drgevent)
        {
            if (drgevent.Data.GetDataPresent("FileDrop"))
                drgevent.Effect = DragDropEffects.Link;
            else
                drgevent.Effect = DragDropEffects.None;
            base.OnDragEnter(drgevent);
        }
        protected override void OnDragLeave(EventArgs e)
        {
            base.OnDragLeave(e);
        }
        #endregion drag & drop related

    }
}
